home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr49 / 130_01.zip / RY.C < prev    next >
Text File  |  1993-06-01  |  24KB  |  899 lines

  1. /********************************************************************
  2.     ry.c - library of file handlers
  3. */
  4.  
  5. /* changes */
  6.  
  7. /*
  8.     following applies to rx package, father of ry:
  9.  
  10.     7/25/81- put this file on seperate development disk, ALL 
  11.     development to this package to be done here only. crl files
  12.     may be spread around as needed.
  13.  
  14.     7/7/81-    made ropen() free allocated buffer space before
  15.     returning on ERROR. Don't close files that return ERROR
  16.     from ropen().
  17.  
  18.     7/7/81- made rclose do primitive close even if buffer not
  19.     flushed correctly, insuring that fd is always freed.
  20.  
  21.     8/18/81- corrected to be grammatically identical to unix
  22.     call syntax (almost, still additional arg to ropen and rcreat
  23.     to explicitly set file buffer size).
  24.  
  25.     2/14/82- add stderr, virtual console, virtual modem, and
  26.     vcon & vmodem to rgetc() and rputc().
  27.  
  28.     3/16/82- remove virtual stuff.
  29.  
  30.     5/30/82 - remove 'byte' and 'string' defines from code
  31.  
  32.     5/30/82 - change all 'FILE' to 'RFILE' for ver 1.46
  33.  
  34.     6/7/82 - fix ropen() setting of fp->_bufbase to '= fp + 1'
  35.  
  36.     7/14/82 - fix rclose to free memory AFTER using fd to free file
  37.  
  38.     9/9/82 - add bs (binary search file) code to package.  got it from
  39.                 bs.c, not fron cnlib, will save cnlib for a while...
  40.             no, maybe I did get it from cnlib....
  41.  
  42.     end of comments/changes on rx stuff
  43.  
  44. */
  45.  
  46. /*
  47.     following applies to ry package:
  48.  
  49.     9/11/82 - change over to ry disk, rename rx files to ry for starters, etc.
  50.                 change fseek() and ftell() to work with 'long' int
  51.                 rename them to lseek() and ltell(), respectively.
  52. */
  53.  
  54. #include "a:std.h"        /* bdscio.h + my stuff */
  55. #include <ry.h>            /* stuff for this package */
  56.  
  57. /*
  58.     purge any old copies, creat and open 'filename', buffer
  59. size equal to secs * size of one sector, mode of write (from
  60. beginning of file), append (write at end of file), or direct
  61. (read or write, starting at beginning of file, random access
  62. to any part of file). read not allowed as you can't read a
  63. new file.
  64. */
  65.  
  66. RFILE *        /* returns pointer to RFILE struct, or ERROR on error */
  67. rcreat(filename, mode, secs)
  68. char *filename;
  69. char mode;
  70. int secs;
  71. {
  72.     int fd;
  73.     char dummy_h[SECSIZ];
  74.     RFILE *ropen();
  75.  
  76.     setmem(dummy_h, SECSIZ, 0);                                /* nulls */
  77.     switch (mode) {
  78.     case 'r':    return ERROR;                        /* can't read empty file */
  79.     case 'w':
  80.     case 'a':
  81.     case 'd':
  82.         if ((fd = creat(filename)) == ERROR ) return ERROR;
  83.         if (write(fd, dummy_h, 1) != 1) {
  84.             fabort(fd);
  85.             return ERROR;                                    /* dummy header */
  86.         }
  87.         if (close(fd) == ERROR) return ERROR;                /* free up fd */
  88.         return ropen(filename, mode, secs);                    /* open */
  89.     default:
  90.         return ERROR;
  91.     }
  92. }
  93. /*
  94.     open 'filename' buffer in space provided by alloc(), setup
  95. fp, buffer of size SECSIZ * secs
  96. */
  97.  
  98. RFILE *        /* returns pointer to RFILE or ERROR on error */
  99. ropen(filename, mode, secs)
  100. char *filename;
  101. char mode;
  102. int secs;
  103. {
  104.     RFILE *fp;
  105.     int fd;
  106.     char *alloc();
  107.     unsigned rcfsiz(), rsrec();
  108.  
  109.     switch (mode) {
  110.     case 'r':                            /* read mode */
  111. /*        fd = open(filename, 0);            /* open read */
  112.         break;
  113. */
  114.     case 'w':                            /* write mode */
  115. /*    case 'a':                            /* append mode */ not supported yet */
  116.     case 'd':                            /* direct or random */
  117.         fd = open(filename, 2);            /* open r/w */
  118.         break;
  119.     default: return ERROR;
  120.     }
  121.     if (fd == ERROR) return ERROR;        /* open error */
  122.  
  123.     if ((fp = alloc(((secs + 1) * SECSIZ) + sizeof(*fp))) == 0) return ERROR;
  124.                                     /* no room for buffer */
  125.     fp -> _rfd = fd;                            /* file descriptor */
  126.     fp -> _bufbase = fp + 1;                    /* start of file buffer */
  127.     fp -> _bufbase += SECSIZ;                    /* room for header */
  128.     fp -> _secs = secs;                            /* secs. in buffer */
  129.     fp -> _nxtbyt = fp -> _bufbase;                  /* start at begin of buf */
  130.     fp -> _pastbuf = fp -> _bufbase + (secs * SECSIZ); /* endbuf */
  131.     fp -> _mode = mode;
  132. /** 'a' not supported yet...
  133.     fp -> _frstsec = (mode == 'a') ?            /* if 'a' start at end */
  134.         rcfsiz(fp->_rfd) : rsrec(fp->_rfd);     /* else at 0 */
  135. **/
  136.     if (read(fd, fp + 1, 1) < 0) {                /* get file header into core */
  137.         free(fp);
  138.         return ERROR;
  139.     }
  140.     fp -> _frstsec = rsrec(fp->_rfd);            /* start at sector 1 */
  141.     if (_fillbuf(fp) == ERROR ) {                /* fill the buffer */
  142.         free(fp);
  143.         return ERROR;
  144.     }
  145.     return fp;
  146. }
  147.  
  148. /*
  149.     flushes, then closes the random file at fp
  150. */
  151.  
  152. rclose(fp)            /* return -1 on error */
  153. RFILE *fp;
  154. {
  155.     int err_flag;
  156.  
  157.     err_flag = _rflush(fp);                                    /* flush buffer */
  158.     if (seek(fp->_rfd, 0, 0) == ERROR) err_flag = ERROR;    /* get to sec 0 */
  159.     if (write(fp->_rfd, fp+1, 1) != 1) err_flag = ERROR;    /* update header */
  160.     if (close(fp->_rfd) == ERROR) err_flag = ERROR;            /* close it */
  161.     free(fp);                                            /* free buffer space */
  162.     return err_flag;                                    /* did it flush ok? */
  163. }
  164. /*
  165.     fills buffer pointed at by fp->_bufbase, with file fp->_rfd,
  166. with fp->_secs sectors, starting with cp/m random record field
  167. lseek calls this after updating cp/m's rrf and fp's pointers (if
  168. necessary because seek is out of buffer area)
  169. */
  170.  
  171. _fillbuf(fp)            /* return -1 on error, 0 if OK */
  172. RFILE *fp;
  173. {
  174.     int fd, secs, got;
  175.     char *base;
  176.     unsigned rseek();
  177.  
  178.     fd = fp -> _rfd;
  179.     secs = fp -> _secs;
  180.     base = fp -> _bufbase;
  181.  
  182. /* call rread for sectors till buffer full or ERROR */
  183.     /* try to read all of buffer */
  184.     while  (secs -= (got = rread(fd, base, secs))) {
  185.         if ((got > 1000) OR (got == -1)) return ERROR;
  186.                                 /* unwritten random sector in buffer area */
  187.         setmem((base += (got * SECSIZ)), SECSIZ, 0);
  188.                                             /* fill this sector with 0's */
  189.         base += SECSIZ;                        /* inc. buffer ptr */
  190.         rseek(fd, 1, 1);                    /* inc. file ptr */
  191.         --secs;                                /* this one filled with 0 */
  192.     }                                        /* try filling rest of buffer */
  193.     fp -> _update = NO;                        /* clear update flag */
  194.     return OK;
  195. }
  196. /*
  197.     flushes the buffer fp->_bufbase if open for writing AND
  198. fp->_update shows the buffer has indeed been written to since
  199. last _fillbuf call. ignores flushes of i/o devices
  200. */
  201.  
  202. _rflush(fp)            /* return -1 on error, 0 if OK */
  203. RFILE *fp;
  204. {
  205.     unsigned rseek();
  206.  
  207.     if ((fp < 4) OR (fp->_mode == 'r') OR (fp->_update == NO))
  208.         return OK;                                            /* don't bother */
  209.     if (rseek(fp -> _rfd,fp -> _frstsec, 0) == ERROR) return ERROR;
  210.                                         /* seek first bufferd sec and ... */
  211.     if (rwrite(fp->_rfd, fp->_bufbase, fp->_secs) != fp->_secs)
  212.         return ERROR;                    /* ...write entire buffer to disk */
  213.     fp -> _update = NO;                    /* clear update flag */
  214.     return OK;
  215. }
  216. /*
  217.     sets '_nxtbyt' of 'fp' to 'offset' (a long int) from
  218. 'origin' , returns offset.
  219. */
  220.  
  221. unsigned    /* returns (long int) offset, -1 on error */
  222. lseek(fp, offset, origin)
  223. RFILE *fp;
  224. char *offset;
  225. int origin;
  226. {
  227.     unsigned sector, byt;
  228.     char longint[4], os[4], os2[4], lsecsiz[4];
  229.     unsigned rseek(), rcfsiz();
  230.     char *ltell();
  231.  
  232.     itol(lsecsiz, SECSIZ);                    /* set logical sector size */
  233.  
  234.     if (origin == 0) {                            /* from beginning of file */
  235.         movmem(offset, os, 4);                    /* make local copy */
  236.     }
  237.     else if (origin == 1) {
  238.         ladd(os, offset, ltell(fp, longint));    /* pres pos + offset to os */
  239.     }
  240.     else if (origin == 3) {                        /* ascii offset from start */
  241.         atol(os, offset);
  242.     }
  243.     else if (origin == 4) {                        /* ascii from pres pos */
  244.         atol(os2, offset);
  245.         ladd(os, os2, ltell(fp, longint));        /* pres pos + offset to os */
  246.     }
  247.     else return ERROR;                            /* only legal orgs now */
  248.     if (os[3] | os[2]) return ERROR;            /* within legal range? */
  249.     ltou(§or, ldiv(longint, os, lsecsiz));    /* byte / secsiz = sectors */
  250.     ltou(&byt, lmod(longint, os, lsecsiz));        /* remainder = bytes */
  251.     ++sector;                                    /* reserve sec 0 for future */
  252.  
  253.     if ((sector >= fp->_frstsec) AND                /* if in buffer */
  254.         (sector < (fp->_frstsec + fp->_secs))) {
  255.         fp->_nxtbyt = (sector - fp->_frstsec)*SECSIZ
  256.             + byt + fp->_bufbase;                    /* point to it */
  257.         return offset;                                /* and return */
  258.     }
  259.     if (_rflush(fp) == ERROR) return ERROR;            /* else flush buf */
  260.     if (rseek(fp->_rfd, sector, 0) == ERROR) return ERROR;
  261.     fp->_frstsec = sector;                            /* seek sec in file, */
  262.     fp->_nxtbyt = byt + fp->_bufbase;                /* and init ptrs */
  263.     if (_fillbuf(fp) == ERROR) return ERROR;        /* fill buf */
  264.     return offset;                                    /* and return */
  265. }
  266. /*
  267.     returns ptr to long int that addresses current file pos.,
  268. or -1 on error.
  269.  
  270. */
  271.  
  272. char *    /* returns ptr to long int */
  273. ltell(fp, longint)
  274. RFILE *fp;
  275. char *longint;
  276. {
  277.     char lb1[4], lb2[4], lfrstsec[4], lsecsiz[4];
  278.  
  279.     itol(lsecsiz, SECSIZ);                    /* set logical sector size */
  280.  
  281.     utol(lfrstsec, (fp->_frstsec - 1));        /* sub for header */
  282.     lmul(lb1, lfrstsec, lsecsiz);            /* times size of sector */
  283.     utol(lb2, fp->_nxtbyt - fp->_bufbase);    /* bytes in buffer to _nxtbyt */
  284.     return ladd(longint, lb1, lb2);            /* add the two */
  285. }
  286.  
  287. /*
  288.     seek a current byte that equals the block size * block #,
  289.     return the current block number or ERROR
  290.     max block # is 65534, large block sizes might cause
  291.     arithmatic overflow before this value is reached
  292. */
  293.  
  294. unsigned        /* returns cur. addressed block, -1 on error */
  295. bseek(fp, block, origin)
  296. RFILE *fp;
  297. unsigned block;
  298. int origin;
  299. {
  300.     unsigned sector;
  301.     char byt;
  302.     int r1, r2, blocksiz;
  303.     char *lseek();
  304.     char longint[4], lblock[4], lbsize[4];
  305.  
  306.     switch (origin) {
  307.     case 0:    break;                            /* from begin */
  308.     case 1:    block += fp->_curblk;            /* from curr pos */
  309.         break;
  310.     case 2:                                    /* from end not supported yet */
  311.     default:
  312.         return ERROR;
  313.     }
  314.     if (block < 0) return ERROR;            /* test under range */
  315.     utol(lblock, block);                    /* make it long int */
  316.     itol(lbsize, fp->_blksiz);
  317.     lmul(longint, lblock, lbsize);
  318. /**
  319.     blocksiz = fp->_blksiz;
  320.     sector = (blocksiz/128)*block + (r1=(blocksiz%128))*(block/128)
  321.             + (r1*(r2=(block%128)))/128; /* need LONG INT */
  322.     byt = r1 * r2 % 128;        /* hope this is right */
  323. **/
  324.     if (lseek(fp, longint, 0) == ERROR) return ERROR;
  325.     return (fp->_curblk = block);
  326. }
  327. /*
  328.     returns the current randomly addressed block
  329.     that is, the last random block sought by
  330.     bseek(), may not reflect _cursec and _curbyt
  331.     if reads or writes have been done since bseek()
  332. */
  333. unsigned                /* returns current log block */
  334. btell(fp)
  335. RFILE *fp;
  336. {
  337.     return (fp->_curblk);
  338. }
  339.  
  340. /*
  341.     returns a char from random buffered file 'fp'
  342. */
  343.  
  344. int            /* returns -1 on error */
  345. rgetc(fp)
  346. RFILE *fp;
  347. {
  348.     if (fp == 0) return getchar();                /* from con */
  349.     if (fp == 3) return bdos(3);                /* from reader */
  350. /*
  351.     if (fp == 5) return cgetchar();                /* to virtual console */
  352.     if (fp == 6) return mgetchar();                /* to virtual modem */
  353.     if (fp == 7) return dgetchar();                /* to both vc & vm */
  354. */
  355.     if (fp->_pastbuf - fp->_nxtbyt)  return *fp->_nxtbyt++;
  356.                                                 /* in buffer */
  357.     if (lseek(fp, "0", 4) == ERROR) return ERROR;
  358.                 /* else seek one byte beyond buf, forcing flush and fill */
  359.     return *fp->_nxtbyt++;                        /* now get it from buffer */
  360. }
  361.  
  362. /*
  363.     random buffered 'unget' a char. Only one call between
  364.     'rgetc()' calls
  365. */
  366.  
  367. int            /* returns OK, -1 on error */
  368. rungetc(c, fp)
  369. char c;
  370. RFILE *fp;
  371. {
  372.     if (fp == 0) return ungetch(c);            /* con */
  373.     lseek(fp, "-1", 4);                        /* back up 1 char */
  374.     rputc(c, fp);                            /* unget the arg */
  375.     lseek(fp, "-1", 4);                        /* prepare to get it */
  376. /**
  377.     if (fp->_nxtbyt <= fp->_bufbase) return ERROR;
  378.                                             /* can't push past begin */
  379.     *--fp->_nxtbyt = c;                        /* do it */
  380. **/
  381.     fp->_update = YES;
  382.     return OK;
  383. }
  384.  
  385. /*
  386.     puts the char 'c' into random buffered file 'fp'
  387. */
  388.  
  389. int            /* returns -1 on error */
  390. rputc(c, fp)
  391. char c;
  392. RFILE *fp;
  393. {
  394.     if (fp->_mode == 'r') return ERROR;            /* cant put in read file */
  395.     if (fp == 1) return putchar(c);                /* to con */
  396.     if (fp == 2) return bdos(5,c);                /* to list */
  397.     if (fp == 3) return bdos(4,c);                /* to punch */
  398.     if (fp == 4) {
  399.         if (c == '\n') bdos(2,'\r');
  400.         return bdos(2,c);
  401.      }    
  402. /*
  403.     if (fp == 5) return cputchar(c);            /* to virtual console */
  404.     if (fp == 6) return mputchar(c);            /* to virtual modem */
  405.     if (fp == 7) return dputchar(c);            /* to both vc & vm */
  406. */
  407.     if (fp->_pastbuf - fp->_nxtbyt) {            /* in buffer */
  408.         fp->_update = YES;                          /* set update */
  409.         return *fp->_nxtbyt++ = c;                /* write it */
  410.     }
  411.     if (lseek(fp, "0", 4) == ERROR) return ERROR; /* flush & fill */
  412.     fp->_update = YES;                               /* set update */
  413.     return *fp->_nxtbyt++ = c;                    /* write it */
  414. }
  415. /*
  416.     returns a 16 bit word from file 'fp'
  417. */
  418.  
  419. int            /* returns -1 on error */
  420. rgetw(fp)
  421. RFILE *fp;
  422. {
  423.     int a,b;    
  424.     if (((a=rgetc(fp)) >= 0) && ((b= rgetc(fp)) >=0))
  425.             return 256*b+a;
  426.     return ERROR;
  427. }
  428. /*
  429.     writes the 16 bit word 'w' to file 'fp'
  430. */
  431.  
  432. int            /* returns -1 on error */
  433. rputw(w, fp)
  434. int w;
  435. RFILE *fp;
  436. {
  437.     if ((rputc(w % 256,fp) >=0 ) && (rputc(w / 256,fp) >= 0))
  438.                 return w;
  439.     return ERROR;
  440. }
  441.  
  442. /*
  443.     gets a TRUE c string (null term.) from file 'fp'
  444. into 'str', returns ptr to 'str'
  445.  
  446. */
  447.  
  448. char *                    /* returns -1 on error */
  449. rgets(str, fp)
  450. char *str;
  451. RFILE *fp;
  452. {
  453.     int count, c;
  454.     char *cptr;
  455.     count = MAXLINE;
  456.     cptr = str;
  457.     while ((count-- - 1) && (c=rgetc(fp)) != EOF && c ) {
  458.         *cptr++ = c;                /* stuff it */
  459.     }
  460.     if (c == EOF) return ERROR;
  461.     *cptr = '\0';                    /* null */
  462.     return str;
  463. }
  464.  
  465. /*
  466.     puts the null terminated c 'str' into 'fp', including null
  467. */
  468.  
  469. rputs(str, fp)            /* returns OK, -1 on error */
  470. char *str;
  471. RFILE *fp;
  472. {
  473.     do {
  474.         if (rputc(*str, fp) == ERROR) return ERROR;
  475.     } while (*str++);
  476.     return OK;
  477. }
  478.  
  479. /*
  480.     gets the LF terminated text from 'fp' into 'line',
  481. stripping off CRs from CR-LF combos
  482.  
  483. */
  484.  
  485. char *            /* returns NULL on error */
  486. rgetl(line, fp)
  487. char *line;
  488. RFILE *fp;
  489. {
  490.     int count, c;
  491.     char *cptr;
  492.     count = MAXLINE;
  493.     cptr = line;
  494.     if ((c = rgetc(fp)) == CPMEOF || c == EOF) return NULL;
  495.  
  496.     do {
  497.         if ((*cptr++ = c) == '\n') {
  498.           if (cptr>line+1 && *(cptr-2) == '\r')
  499.             *(--cptr - 1) = '\n';
  500.           break;
  501.         }
  502.      } while (count-- && (c=rgetc(fp)) != EOF && c != CPMEOF);
  503.  
  504.     if (c == CPMEOF) rungetc(c, fp);    /* push back control-Z */
  505.     *cptr = '\0';
  506.     return line;
  507. }
  508.  
  509. /*
  510.     puts string at 'line' into 'fp', converting LFs to CR-LFs
  511. if no LF exists no terminator (crlf) is written (ala fputs)
  512.  
  513. */
  514.  
  515. rputl(line, fp)            /* returns OK, -1 on error */
  516. char *line;
  517. RFILE *fp;
  518. {
  519.     char c;
  520.     while (c = *line++) {
  521.         if (c == '\n') {
  522.             if (rputc('\r', fp) == ERROR) return ERROR;
  523.         }
  524.         if (rputc(c, fp) == ERROR) return ERROR;
  525.     }
  526.     return OK;
  527. }
  528.  
  529. /*
  530.     gets 'nbyts' into memory starting at 'destination' from
  531. file in 'fp'
  532. */
  533.  
  534. char *                /* returns -1 on error */
  535. rget(fp, destination, nbyt)
  536. RFILE *fp;
  537. char *destination;
  538. unsigned nbyt;
  539. {
  540.     char b, *ptr;
  541.  
  542.     ptr = destination;
  543.     while (nbyt--) {
  544.         if ((b = rgetc(fp)) == ERROR) return ERROR;
  545.         *ptr++ = b;
  546.     }
  547.     return destination;
  548. }
  549. /*
  550.     puts 'nbyts' into file 'fp' from 'source'
  551. */
  552.  
  553. rput(fp, source, nbyt)            /* returns OK, -1 on error */
  554. RFILE *fp;
  555. char *source;
  556. unsigned nbyt;
  557. {
  558.     while (nbyt--) {
  559.         if (rputc(*source++, fp) == ERROR) return ERROR;
  560.     }
  561.     return OK;
  562. }
  563.  
  564. /*
  565.     gets struct 'structsiz' long into memory starting at 'struct_add'
  566. from file in 'fp'
  567. */
  568.  
  569. char *                    /* returns -1 on error */
  570. rgetstruct(fp, struct_add, structsiz)
  571. RFILE *fp;
  572. char *struct_add;
  573. unsigned structsiz;
  574. {
  575.     char b, *ptr;
  576.  
  577.     ptr = struct_add;
  578.     while (structsiz--) {
  579.         if ((b = rgetc(fp)) == ERROR) return ERROR;
  580.         *ptr++ = b;
  581.     }
  582.     return struct_add;
  583. }
  584. /*
  585.     puts struct 'structsiz' long into file 'fp' from 'struct_add'
  586. */
  587.  
  588. rputstruct(fp, struct_add, structsiz)    /* returns OK, -1 on error */
  589. RFILE *fp;
  590. char *struct_add;
  591. unsigned structsiz;
  592. {
  593.     while (structsiz--) {
  594.         if (rputc(*struct_add++, fp) == ERROR) return ERROR;
  595.     }
  596.     return OK;
  597. }
  598. /*
  599.     printf to random buffered file
  600. */
  601.  
  602. int            /* returns OK, -1 on error */
  603. rprintf(fp, format)
  604. RFILE *fp;
  605. char *format;
  606. {
  607.     char text[MAXLINE];
  608.     _spr(text,&format);
  609.     return rputl(text,fp);
  610. }
  611.  
  612. /*
  613.     scanf to random buffered file
  614. */
  615.  
  616. int            /* returns # of successful matches, 0 on EOF */
  617. rscanf(fp, format)
  618. RFILE *fp;
  619. char *format;
  620. {
  621.     char text[MAXLINE];
  622.     if (!rgetl(text,fp)) return 0;
  623.     return _scn(text,&format);
  624. }
  625.  
  626. /* end of the random buffered file code.... */
  627.  
  628.  
  629. /* start of bs code... */
  630.  
  631. bsmake(data_file, ptr_file, data_size, max_data)
  632. char *data_file;
  633. char *ptr_file;
  634. int data_size;
  635. int max_data;
  636. {
  637.     RFILE *fp;
  638.  
  639.     if (data_size < 8) return ERROR;                /* (to hold four ints) */
  640.     if ((fp = rcreat(data_file, 'd', 1)) == ERROR)
  641.         return ERROR;                                /* creat a data file */
  642.     rputw(0, fp);                                /* 0 data elements in file */
  643.     rputw(0, fp);                                /* empty free list */
  644.     rputw(data_size, fp);                        /* block size of data file */
  645.     rputw(max_data, fp);                        /* max elements in data file */
  646.         /* note: core must be able to hold twice this number of bytes. kinda
  647.             limited but for files with a few thousand elements i suppose it
  648.             will do.
  649.         */
  650.  
  651.     rclose(fp);                                        /* close datafile */
  652.     if ((fp = rcreat(ptr_file, 'd', 1)) == ERROR)        /* creat a ptr file */
  653.         return ERROR;
  654.     rputw(0, fp);                        /* write 0 to ptr file, not sure why */
  655.     rclose(fp);                            /* close ptr file */
  656. }
  657.  
  658. bsopen(data_file, ptr_file, key_comp, secs)
  659. char *data_file;
  660. char *ptr_file;
  661. int (*key_comp)();
  662. int secs;
  663. {
  664.     BSFILE *bsp;
  665.     RFILE *fp;
  666.     int array_size;
  667.  
  668.     if ((fp = ropen(data_file, 'd', secs)) == ERROR)    /* open data file */
  669.         return ERROR;
  670.     lseek(fp, "6", 3);                            /* find fourth int in file */
  671.     array_size = rgetw(fp);                        /* max elements in data file */
  672.     array_size = (((array_size * 2) + (SECSIZ - 1)) / SECSIZ); /* sectors */
  673.     if ((bsp = alloc(array_size * SECSIZ + sizeof(*bsp))) == 0) {
  674.         rclose(fp);
  675.         return ERROR;
  676.     }
  677.                             /* init struct bs */
  678.     bsp->_dfp = fp;                        /* fp to 'data_file' */
  679.     strcpy(bsp->_pfname, ptr_file);        /* save the name for closing */
  680.     bsp->_key_comp = key_comp;            /* pointer to appropriate comp funct */
  681.     lseek(fp, "0", 3);                    /* go to beginning of file */
  682.     bsp->_data_num = rgetw(fp);            /* number of data items in file */
  683.     rgetw(fp);                            /* skip free list */
  684.     fp->_blksiz = bsp->_data_size = rgetw(fp);
  685.                         /* size in bytes of a data item, set up block seeks */
  686.     bsp->_max_data = rgetw(fp);            /* maximum data elements in ptr file */
  687.     bsp->_data_ptr = 0;                    /* set by last call to search() */
  688.     bsp->_ptr_array = bsp + 1;            /* base of pointer array */
  689.     if (xswapin(ptr_file, bsp->_ptr_array, array_size) == ERROR) {
  690.         rclose(fp);                        /* fill the ptr array */
  691.         free(bsp);
  692.         return ERROR;
  693.     }
  694.     return bsp;
  695. }
  696.  
  697. bsclose(bsp)
  698. BSFILE *bsp;
  699. {
  700.     xswapout(bsp->_pfname, bsp->_ptr_array, 
  701.         ((bsp->_max_data * 2) + (SECSIZ - 1)) / SECSIZ);         /* sectors */
  702.     lseek(bsp->_dfp, "0", 3);                /* seek beginning of data file */
  703.     rputw(bsp->_data_num, bsp->_dfp);        /* and write data_num to it */
  704.     rclose(bsp->_dfp);                        /* close data file */
  705.     free(bsp);
  706. }
  707.  
  708. bsread(bsp, key, address)
  709. BSFILE *bsp;
  710. char *key;
  711. char *address;
  712. {
  713.     int result;
  714.  
  715.     if (key[0]) {                             /* if key is given, search first */
  716.         switch (bssearch(bsp, key)) {
  717.         case BELONGS:    return BELONGS;
  718.         case FOUND:        rget(bsp->_dfp, address, bsp->_data_size);
  719.                         return FOUND;
  720.         case ERROR:
  721.         default:        return ERROR;
  722.         }
  723.     }
  724.     else {                                    /* seek the proper block */
  725.         if (bseek(bsp->_dfp, bsp->_data_ptr, 0) == ERROR)
  726.             return ERROR;
  727.         rget(bsp->_dfp, address, bsp->_data_size);
  728.         return OK;
  729.     }
  730. }
  731.  
  732. bswrite(bsp, key, address)
  733. BSFILE *bsp;
  734. char *key;
  735. char *address;
  736. {
  737.     int result;
  738.  
  739.     if (key[0]) {                             /* if key is given, search first */
  740.         switch (bssearch(bsp, key)) {
  741.         case BELONGS:    if (bskey_add(bsp) == ERROR) return ERROR;
  742.                         rput(bsp->_dfp, address, bsp->_data_size);
  743.                         return BELONGS;
  744.         case FOUND:        rput(bsp->_dfp, address, bsp->_data_size);
  745.                         return FOUND;
  746.         case ERROR:
  747.         default:        return ERROR;
  748.         }
  749.     }
  750.     else {                                    /* seek the proper block */
  751.         if (bseek(bsp->_dfp, bsp->_data_ptr, 0) == ERROR)
  752.             return ERROR;
  753.         rput(bsp->_dfp, address, bsp->_data_size);
  754.         return OK;
  755.     }
  756. }
  757.  
  758. bssearch(bsp, key)
  759. BSFILE *bsp;
  760. char *key;
  761. {
  762.     int bottom, middle, top, result;
  763.     char block_key[MAXLINE];
  764.  
  765.     bottom = middle = 1; top = bsp->_data_num;
  766.     while (top >= bottom) {                        /* till tail passes head... */
  767.         middle = (top + bottom) / 2;                    /* find midpoint */
  768.         if (bseek(bsp->_dfp, bsp->_ptr_array[middle], 0) == ERROR)
  769.                 return ERROR;                            /* record it pts to */
  770.         rgets(block_key, bsp->_dfp);                    /* read the key */
  771.         result = (*bsp->_key_comp)(key, block_key);        /* compare them */
  772.         if (result > 0) bottom = ++middle;        /* it would go in NEXT slot */
  773.         else if (result < 0) top = middle - 1;    /* it would go HERE */
  774.         else {                /* set _data_ptr to log. block containing record */
  775.             if (bseek(bsp->_dfp, bsp->_data_ptr = bsp->_ptr_array[middle], 0)
  776.                 == ERROR) return ERROR;                /* seek the proper block */
  777.             bsp->_array_index = middle;
  778.             return FOUND;
  779.         }
  780.     }
  781.     bsp->_array_index = middle;                        /* not found, */
  782.     return BELONGS;                                    /* belongs here */
  783. }
  784.  
  785. bskey_add(bsp)
  786. BSFILE *bsp;
  787. {
  788.       if (++bsp->_data_num > bsp->_max_data) {
  789.         --bsp->_data_num;
  790.         return ERROR;                                /* no room */
  791.     }
  792.     if (bsblk_add(bsp) == ERROR) {
  793.         --bsp->_data_num;
  794.         return ERROR;
  795.     }
  796.     if (bseek(bsp->_dfp, bsp->_data_ptr, 0) == ERROR)
  797.         return ERROR;
  798.     movmem(&bsp->_ptr_array[bsp->_array_index],        /* open hole */
  799.         &bsp->_ptr_array[bsp->_array_index + 1],
  800.         (bsp->_data_num - bsp->_array_index) * 2);
  801.     bsp->_ptr_array[bsp->_array_index] = bsp->_data_ptr; /* add ptr */
  802.     return OK;
  803. }
  804.  
  805. bsblk_add(bsp)
  806. BSFILE *bsp;
  807. {
  808.     int free_ptr;
  809.  
  810.     lseek(bsp->_dfp, "2", 3);            /* find second int in file */
  811.     if (!(bsp->_data_ptr = rgetw(bsp->_dfp))) {    /* free list ptr */
  812.         bsp->_data_ptr = bsp->_data_num;        /* nope, end block */
  813.     }
  814.     else {
  815.         if (bseek(bsp->_dfp, bsp->_data_ptr, 0) == ERROR)
  816.             return ERROR;
  817.         free_ptr = rgetw(bsp->_dfp);
  818.         lseek(bsp->_dfp, "2", 3);        /* find second int in file */
  819.         rputw(free_ptr, bsp->_dfp);        /* record top of free list */
  820.     }
  821.     return OK;
  822. }
  823.  
  824. bskey_rmv(bsp, key)
  825. BSFILE *bsp;
  826. char *key;
  827. {
  828.     int result;
  829.  
  830.     if ((result = bssearch(bsp, key)) != FOUND) return result;
  831.     movmem(&bsp->_ptr_array[bsp->_array_index + 1],        /* close hole */
  832.         &bsp->_ptr_array[bsp->_array_index],
  833.         (bsp->_data_num - bsp->_array_index) * 2);
  834.     --bsp->_data_num;                                /* decrement the count */
  835.     bsblk_rmv(bsp);                                /* return to free list */
  836.     return OK;
  837. }
  838.  
  839. bsblk_rmv(bsp)
  840. BSFILE *bsp;
  841. {
  842.     int free_ptr;
  843.  
  844.     lseek(bsp->_dfp, "2", 3);                /* find second int in file */
  845.     free_ptr = rgetw(bsp->_dfp);            /* read free ptr from data file */
  846.     if (bseek(bsp->_dfp, bsp->_data_ptr, 0) == ERROR)
  847.         return ERROR;                        /* seek freed block */
  848.     rputw(free_ptr, bsp->_dfp);                /* write free ptr to freed block */
  849.     lseek(bsp->_dfp, "2", 3);                /* find second int in file */
  850.     rputw(bsp->_data_ptr, bsp->_dfp);
  851.                                     /* write block to data file (free ptr) */
  852.     return OK;
  853. }
  854.  
  855. /* end of the bs code.... */
  856.  
  857. /*
  858.     these 2 are an expansion of the standard 'swapin()', allow
  859.     the size of core to be specified, insuring that other things
  860.     wont be clobbered.  a 'swapout()' has been added for updating
  861.     the file back to disk
  862. */
  863.  
  864. xswapin(name, addr, sectors)
  865. char *name;        /* the file to swap in */
  866. unsigned addr;
  867. int sectors;
  868. {
  869.     int fd, x;
  870.     if (( fd = open(name,0)) == ERROR) {
  871.         return ERROR;
  872.     }
  873.     if ((x = read(fd,addr,sectors)) < 0) {
  874.         close(fd);
  875.         return ERROR;
  876.     }
  877.     close(fd);
  878.     return OK;
  879. }
  880.  
  881. /* add temp file and rename someday.... */
  882.  
  883. xswapout(name, addr, sectors)
  884. char *name;        /* the file to swap out */
  885. unsigned addr;
  886. int sectors;
  887. {
  888.     int fd, x;
  889.     if (( fd = open(name,1)) == ERROR) {
  890.         return ERROR;
  891.     }
  892.     if ((x = write(fd,addr,sectors)) < 0) {
  893.         close(fd);
  894.         return ERROR;
  895.     }
  896.     close(fd);
  897.     return OK;
  898. }
  899. >_dfp, "2", 3);                /* find s